#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
//#include <errno.h> 

int getfsuid(uid_t *fsuid) 
{ 
	pid_t pid; 
	char filename[1024], str[1024], *str2; 
	FILE *fp; 
	int i; 


	if ((pid = getpid()) < 0) 
	{ 
		perror("getpid()");
		exit(1);
	} 
	sprintf(filename, "/proc/%u/status", pid);
	if ((fp = fopen(filename, "r")) == NULL) 
	{ 
		perror("fopen()");
		exit(1); 
	} 
	while (fgets(str, 1023, fp) != NULL) 
	 { 
		if ((str2 = strstr(str, "Uid:")) == str)
		{ 
			strtok(str, "\t");
			for (i = 0; i < 4; i++)
			str2 = strtok(NULL, "\t");
			*fsuid = atoi(str2);
			fclose(fp);
			return 0;
		} 
	} 
return -1; 
}



void usage()
{
	printf("\nUSAGE: aprun [-rRUID] [-eEUID] [-sSUID] [-fFSUID] [-h] [PROC]\n\n");
	printf("aprun: \t  Assign Privilege and then RUN proc\n");
	printf("OPTIONS:\n");
	printf("\t -rRUID \t set real-user-id to RUID\n");
	printf("\t -eEUID \t set effective-user-id to EUID\n");
	printf("\t -sSUID \t set saved-set-user-id to SUID\n");
	printf("\t -fFSUID \t set real-user-id to FSUID\n");
	printf("\t -h      \t print this help info\n");
	printf("PROC: program to be called, default is /bin/bash\n\n");
}

int main(int argc, char** argv) 
{
	uid_t ruid, euid, suid, fsuid;

/* show the current uids */
	if( (getresuid(&ruid, &euid, &suid))<0 )
	{
		perror("getresuid() failed!");
		exit(1);
	}
	if( (getfsuid(&fsuid))<0 )
	{
		perror("getfsuid() failed!");
		exit(1);
	}	
	printf("CURRENT real-user-id=%d\t",ruid);
	printf("effective-user-id=%d\t",euid);
	printf("saved-set-user-id=%d\t",suid);
	printf("fs-user-id=%d\n",fsuid);


/* get new uids from args */

	ruid=euid=suid=fsuid=-1;	// -1 means remaining the same
	int opt;
	while( (opt=getopt(argc, argv, "r:e:s:f:h")) != -1)
	{
		switch(opt)
		{
		case 'r':
			ruid=atoi(optarg);
			break;
		case 'e':
			euid=atoi(optarg);
			break;
		case 's':
			suid=atoi(optarg);
			break;
		case 'f':
			fsuid=atoi(optarg);
			break;
		case 'h':
			usage();
			return 0;
		default:
			printf("optarg=\"%s\", optind=%d, optopt='%c'\n",optarg, optind, optopt);
			usage();
		}
	}

/* update uids */

	if(ruid!=-1 || euid!=-1 || suid!=-1)
	{
		if( (setresuid(ruid,euid,suid))==0 )
			printf("setresuid(%d,%d,%d) SUCCESS!\n",ruid,euid,suid);
		else
			perror("setresuid() FAILED!");
	}
	if(fsuid!=-1)
	{
		if( (setfsuid(fsuid))==0 )
			printf("setfsuid(%d) SUCCESS!\n",fsuid);
		else
			perror("setfsuid() FAILED!");
	}


/* show the current uids */
	if( (getresuid(&ruid, &euid, &suid))<0 )
	{
		perror("getresuid() failed!");
		exit(1);
	}
	if( (getfsuid(&fsuid))<0 )
	{
		perror("getfsuid() failed!");
		exit(1);
	}		
	printf("CURRENT real-user-id=%d\t",ruid);
	printf("effective-user-id=%d\t",euid);
	printf("saved-set-user-id=%d\t",suid);
	printf("fs-user-id=%d\n",fsuid);

/* set the program to be called */
	char** proc;
	char* default_proc[]={"/bin/bash","-p",NULL};
	if(optind==argc)
		proc=default_proc;
	else if(optind<argc)
		proc=argv+optind;
	else
	{
		perror("optind>argc");
		exit(2);
	}

/* show the program to be called */		
	printf("Now I'm calling.......\n");
	int i=0;
	while(proc[i]!=NULL)
		printf("%s ",proc[i++]);	
	printf("\n\n");
	
/* call program with new uids */
	execvp(proc[0],proc);
	exit(0);
}
